package usergroup

import (
	"context"

	v1 "gitee.com/liangziyisheng/caas-platform-mc/api/usergroup/v1"
	"gitee.com/liangziyisheng/caas-platform-mc/internal/consts"
	"gitee.com/liangziyisheng/caas-platform-mc/internal/dao"
	"gitee.com/liangziyisheng/caas-platform-mc/internal/model/entity"
	"gitee.com/liangziyisheng/caas-platform-mc/internal/service"

	"github.com/gogf/gf/v2/errors/gcode"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/glog"
)

type sUserGroup struct{}

var l = g.Log("logger for UserGroup")

func New() *sUserGroup {
	return &sUserGroup{}
}

func init() {
	l.SetFlags(glog.F_FILE_LONG)
	service.RegisterUserGroup(New())
}

func (s *sUserGroup) List(ctx context.Context, in *v1.ListInput) (out *v1.ListOutput, err error) {
	ugcls := dao.UserGroup.Columns()
	md := dao.UserGroup.Ctx(ctx).Where(ugcls.TenantCode, in.TenantCode)
	if in.Name != "" {
		md = md.Where(ugcls.Name, in.Name)
	}
	if in.TenantCode != "" {
		md = md.Where(ugcls.TenantCode, in.TenantCode)
	}
	out = &v1.ListOutput{}
	err = md.Limit((in.Page-1)*in.Size, in.Size).ScanAndCount(&out.Data, &out.Total, true)
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.ListFailed, in))
	}
	return out, nil
}
func (s *sUserGroup) Info(ctx context.Context, in *v1.InfoInput) (out *v1.InfoOutput, err error) {
	// return nil, nil
	out = &v1.InfoOutput{Users: make([]entity.User, 0), Id: in.Id}
	// 首先确定用户组存在
	ugcls := dao.UserGroup.Columns()
	ug := entity.UserGroup{}
	err = dao.UserGroup.Ctx(ctx).Where(ugcls.TenantCode, in.TenantCode).Where(ugcls.Id, in.Id).Scan(&ug)
	if err != nil || ug.Id == 0 {
		l.Error(ctx, err)
		return nil, gerror.NewCodef(consts.UserGroupNotExist, consts.UserGroupNotExist.Message(), in.Id)
	}
	// 查询用户id
	gucls := dao.GroupUser.Columns()
	usersId, err := dao.GroupUser.Ctx(ctx).Fields(gucls.UserId).Where(gucls.GroupId, in.Id).Array()
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCodef(consts.QueryGroupUserFailed, consts.QueryGroupUserFailed.Message(), in.Id)
	}
	if len(usersId) != 0 {
		ucls := dao.User.Columns()
		err = dao.User.Ctx(ctx).Where(ucls.TenantCode, in.TenantCode).WhereIn(ugcls.Id, usersId).Scan(&out.Users)
		if err != nil {
			l.Error(ctx, err)
			return nil, gerror.NewCode(consts.QueryUserFailed)
		}
	}
	return out, nil
}

func (s *sUserGroup) Add(ctx context.Context, in *v1.AddInput) (out *v1.AddOutput, err error) {
	id, err := dao.UserGroup.Ctx(ctx).InsertAndGetId(in.UserGroup)
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.AddFailed, in.UserGroup))
	}
	return &v1.AddOutput{Id: id}, nil
}

func (s *sUserGroup) Delete(ctx context.Context, in *v1.DeleteInput) (out *v1.DeleteOutput, err error) {

	// 先检查是否存在用户关联
	us, err := dao.GroupUser.Ctx(ctx).Where(dao.GroupUser.Columns().GroupId, in.Id).Count()
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.QueryUserGroupFailed, in.Id))
	}
	if us > 0 {
		return nil, gerror.NewCode(consts.UserAssignedInGroup)
	}
	ugcls := dao.UserGroup.Columns()
	rs, err := dao.UserGroup.Ctx(ctx).Where(ugcls.Id, in.Id).Where(ugcls.TenantCode, in.TenantCode).Delete()
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.DeleteFailed, in.Id))
	}
	out = &v1.DeleteOutput{}
	if out.Rows, err = rs.RowsAffected(); err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.DeleteFailed, in.Id))
	}
	if out.Rows == 0 {
		return nil, gerror.NewCode(gcode.WithCode(consts.DeleteFailed, in.Id))
	}

	return out, nil
}

func (s *sUserGroup) Update(ctx context.Context, in *v1.UpdateInput) (out *v1.UpdateOutput, err error) {
	out = &v1.UpdateOutput{}
	ugcls := dao.UserGroup.Columns()
	out.Rows, err = dao.UserGroup.Ctx(ctx).Data(in.UserGroup).Where(ugcls.Id, in.Id).Where(ugcls.TenantCode, in.TenantCode).UpdateAndGetAffected()
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.UpdateFailed, in.UserGroup))
	}
	if out.Rows == 0 {
		return nil, gerror.NewCode(gcode.WithCode(consts.DeleteFailed, in.Id))
	}
	return out, nil
}

func (s *sUserGroup) AssignUser(ctx context.Context, in *v1.AssignUserInput) (out *v1.AssignUserOutput, err error) {
	if len(in.Users) == 0 {
		return &v1.AssignUserOutput{Id: 0}, nil
	}
	// 确定用户组和用户都存在
	ucls := dao.User.Columns()
	ugcls := dao.UserGroup.Columns()
	rows := 0
	rows, err = dao.User.Ctx(ctx).WhereIn(ucls.Id, in.Users).Where(ucls.TenantCode, in.TenantCode).Count()
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.AssignUserToGroupFailed, in))
	}
	if rows != len(in.Users) {
		return nil, gerror.NewCode(gcode.WithCode(consts.UserNotExist, in))
	}
	rows, err = dao.UserGroup.Ctx(ctx).Where(ugcls.Id, in.Id).Where(ugcls.TenantCode, in.TenantCode).Count()
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.AssignUserToGroupFailed, in))
	}
	if rows == 0 {
		return nil, gerror.NewCodef(consts.UserGroupNotExist, consts.UserGroupNotExist.Message(), in.Id)
	}

	gus := make([]entity.GroupUser, 0)
	for _, uid := range in.Users {
		gus = append(gus, entity.GroupUser{
			GroupId: in.Id,
			UserId:  uid,
		})
	}
	out = &v1.AssignUserOutput{}
	out.Id, err = dao.GroupUser.Ctx(ctx).Data(gus).InsertAndGetId()
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.AssignUserToGroupFailed, gus))
	}
	return out, nil
}

func (s *sUserGroup) UnassignUser(ctx context.Context, in *v1.UnassignUserInput) (out *v1.UnassignUserOutput, err error) {
	if len(in.Users) == 0 {
		return &v1.UnassignUserOutput{Rows: 0}, nil
	}
	ucls := dao.User.Columns()
	ugcls := dao.UserGroup.Columns()
	rows := 0
	rows, err = dao.User.Ctx(ctx).WhereIn(ucls.Id, in.Users).Where(ucls.TenantCode, in.TenantCode).Count()
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.AssignUserToGroupFailed, in))
	}
	if rows != len(in.Users) {
		return nil, gerror.NewCode(gcode.WithCode(consts.UserNotExist, in))
	}
	rows, err = dao.UserGroup.Ctx(ctx).Where(ugcls.Id, in.Id).Where(ugcls.TenantCode, in.TenantCode).Count()
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.AssignUserToGroupFailed, in))
	}
	if rows == 0 {
		return nil, gerror.NewCodef(consts.UserGroupNotExist, consts.UserGroupNotExist.Message(), in.Id)
	}

	out = &v1.UnassignUserOutput{}
	rs, err := dao.GroupUser.Ctx(ctx).Where(dao.GroupUser.Columns().GroupId, in.Id).WhereIn(dao.GroupUser.Columns().UserId, in.Users).Delete()
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.UnassignUserToGroupFailed, in))
	}
	if out.Rows, err = rs.RowsAffected(); err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.UnassignUserToGroupFailed, in))
	}

	return out, nil
}
